/*
 *  (c) 2015 fullhan.com
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 * MA 02111-1307 USA
 */




/*****************************************************************************
 *  Include Section
 *  add all #include here
 *****************************************************************************/
#include <common.h>
#include <command.h>
#include <net.h>
#include <malloc.h>
#include <linux/compiler.h>
#include "fh_qos_gmac.h"
#include <phy.h>
#include <miiphy.h>
#include <asm/arch/hardware.h>
#include "net_auto_dll_tuning.h"
/*****************************************************************************
 * Define section
 * add all #define here
 *****************************************************************************/
#define __qos_raw_writeb(v, a) (*(volatile unsigned char *)(a) = (v))
#define __qos_raw_writew(v, a) (*(volatile unsigned short *)(a) = (v))
#define __qos_raw_writel(v, a) (*(volatile unsigned int *)(a) = (v))
#define __qos_raw_readb(a) (*(volatile unsigned char *)(a))
#define __qos_raw_readw(a) (*(volatile unsigned short *)(a))
#define __qos_raw_readl(a) (*(volatile unsigned int *)(a))

#define dw_readl(dw, name) \
    __qos_raw_readl(&(((struct dw_qos_regs_map *)dw->regs)->name))
#define dw_writel(dw, name, val) \
    __qos_raw_writel((val), &(((struct dw_qos_regs_map *)dw->regs)->name))
#define dw_readw(dw, name) \
    __qos_raw_readw(&(((struct dw_qos_regs_map *)dw->regs)->name))
#define dw_writew(dw, name, val) \
    __qos_raw_writew((val), &(((struct dw_qos_regs_map *)dw->regs)->name))

#define DWCQOS_FOR_EACH_QUEUE(max_queues, queue_num)			\
		for (queue_num = 0; queue_num < max_queues; queue_num++)

#define FH_QOS_ASSERT(expr) if (!(expr)) { \
        printf("Assertion failed! %s:line %d\n", \
        __func__, __LINE__); \
        while (1)   \
           ;       \
        }

#ifndef BIT
#define BIT(x)	(1 << (x))
#endif

#ifndef CACHE_LINE_SIZE
#define CACHE_LINE_SIZE		64
#endif

#define DWCQOS_MAC_RX_POS		BIT(0)
#define DWCQOS_MAC_TX_POS		BIT(1)

#define DWCQOS_DMA_MODE_SWR      BIT(0)
#define DWCQOS_DMA_RDES3_OWN     BIT(31)
#define DWCQOS_DMA_RDES3_INTE    BIT(30)
#define DWCQOS_DMA_RDES3_BUF2V   BIT(25)
#define DWCQOS_DMA_RDES3_BUF1V   BIT(24)

#define DWCQOS_DMA_CH_CTRL_PBLX8       BIT(16)
#define DWCQOS_DMA_CH_TX_TSE           BIT(12)

#define DWCQOS_MTL_TXQ_TXQEN            BIT(3)
#define DWCQOS_MTL_TXQ_TSF              BIT(1)
#define DWCQOS_MTL_TXQ_TTC512           0x00000070
#define DWCQOS_MTL_RXQ_FUP              BIT(3)
#define DWCQOS_MTL_RXQ_FEP              BIT(4)
#define DWCQOS_MTL_RXQ_RSF              BIT(5)

#define DWCQOS_MTL_TXQ_DEBUG_TRCSTS_READ_STATE	BIT(1)
#define DWCQOS_MTL_TXQ_DEBUG_TRCSTS_MASK	(0x3 << 1)
//txq empty
#define DWCQOS_MTL_TXQ_DEBUG_TXQSTS	BIT(4)


#define DWCQOS_MTL_RXQ_DEBUG_ACTIVE_PACKET_POS_MASK		(0x3fff < 16)
#define DWCQOS_MTL_RXQ_DEBUG_RXQSTS_MASK		(0x3 << 4)
#define DWCQOS_MTL_RXQ_DEBUG_RXQSTS_EMPTY	(0)


#define DWCQOS_DMA_RDES1_IPCE    BIT(7)
#define DWCQOS_DMA_RDES1_IPHE    BIT(3)
#define DWCQOS_DMA_RDES3_ES      BIT(15)

#define DWCQOS_DMA_TDES2_IOC     BIT(31)
#define DWCQOS_DMA_TDES3_OWN     BIT(31)
#define DWCQOS_DMA_TDES3_FD      BIT(29)
#define DWCQOS_DMA_TDES3_LD      BIT(28)
#define GMAC_TIMEOUT_SEND		(100000)		//100ms

#define RX_DESC_NUM CONFIG_SYS_RX_ETH_BUFFER
#define TX_DESC_NUM 20
#define MAX_EACH_DESC_XFER_SIZE	16380
#define MAX_TSO_SEGMENT_SIZE	0x20000

#define FORCE_ACTIVE_QUEUE_INDEX	0

/****************************************************************************
 * ADT section
 *  add definition of user defined Data Type that only be used in this file  here
 ***************************************************************************/
/* Hardware register definitions. */
struct dw_qos_dma_channel_regs{
	u32 control;
	u32 tx_control;
	u32 rx_control;
	u32 reserved_0;
	u32 txdesc_list_haddr;
	u32 txdesc_list_laddr;
	u32 rxdesc_list_haddr;
	u32 rxdesc_list_laddr;
	u32 txdesc_tail_pointer;
	u32 reserved_1;
	u32 rxdesc_tail_pointer;
	u32 txdesc_ring_len;
	u32 rxdesc_ring_len;
	u32 interrupt_enable;
	u32 rx_interrupt_wdt_timer;
	u32 slot_func_control_status;
	u32 reserved_2;
	u32 current_app_txdesc;
	u32 reserved_3;
	u32 current_app_rxdesc;
	u32 current_app_txbuf_haddr;
	u32 current_app_txbuf_laddr;
	u32 current_app_rxbuf_haddr;
	u32 current_app_rxbuf_laddr;
	u32 status;
	u32 reserved_4[2];
	u32 miss_frame_cnt;
	u32 reserved_5[4];
};

struct dw_qos_dma_regs
{
	u32 mode;
	u32 sysbus_mode;
	u32 interrupt_status;
	u32 debug_status0;
	u32 debug_status1;
	u32 debug_status2;
	u32 reserved_0[2];
	u32 tx_ar_ace_control;
	u32 rx_aw_ace_control;
	u32 txrx_awar_ace_control;
	u32 reserved_1[53];
	struct dw_qos_dma_channel_regs chan[8];
};


/* mtl register */
struct dw_qos_mtl_queue_0_regs{
	u32 txq_operation_mode;
	u32 txq_underflow;
	u32 txq_debug;
	u32 reserved_0[2];
	u32 txq_ets_status;
	u32 txq_quantum_weight;
	u32 reserved_1[4];
	u32 interrupt_control_status;
	u32 rxq_operation_mode;
	u32 rxq_missed_packet_overflow_cnt;
	u32 rxq_debug;
	u32 rxq_control;
};

struct dw_qos_mtl_queue_1_regs{
	u32 txq_operation_mode;
	u32 txq_underflow;
	u32 txq_debug;
	u32 reserved_0;
	u32 txq_ets_control;
	u32 txq_ets_status;
	u32 txq_quantum_weight;
	u32 txq_send_slope_credit;
	u32 txq_hi_credit;
	u32 txq_lo_credit;
	u32 reserved_1;
	u32 interrupt_control_status;
	u32 rxq_operation_mode;
	u32 rxq_missed_packet_overflow_cnt;
	u32 rxq_debug;
	u32 rxq_control;
};

struct dw_qos_mtl_regs
{
	u32 operation_mode;
	u32 reserved_0;
	u32 debug_control;
	u32 debug_status;
	u32 fifo_debug_data;
	//doc bug...
	u32 reserved_1[3];

	u32 interrupt_status;
	u32 reserved_2[3];

	u32 rxq_dma_map0;
	u32 rxq_dma_map1;
	u32 reserved_3[50];

	struct dw_qos_mtl_queue_0_regs q_0;
	struct dw_qos_mtl_queue_1_regs q_x[7];
	u32 reserved_4[64];
};


/* mac register */
struct dw_mac_addr{
	u32 addr_hi;
	u32 addr_lo;
};

struct dw_mac_mmc_regs{
	u32 control;
	u32 rx_interrupt;
	u32 tx_interrupt;
	u32 rx_interrupt_mask;
	u32 tx_interrupt_mask;
	u32 tx_octet_cnt_good_bad;
	u32 tx_packet_cnt_good_bad;
	u32 tx_broadcast_packet_good;
	u32 tx_multi_packet_good;
	u32 tx_64_octet_packet_good_bad;
	u32 tx_65_127_octet_packet_good_bad;
	u32 tx_128_255_octet_packet_good_bad;
	u32 tx_256_511_octet_packet_good_bad;
	u32 tx_512_1023_octet_packet_good_bad;
	u32 tx_1024_max_octet_packet_good_bad;
	u32 tx_unicast_packet_good_bad;
	u32 tx_multicast_packet_good_bad;
	u32 tx_broadcast_packet_good_bad;
	u32 tx_underflow_err_packet;
	u32 tx_single_collision_packet;
	u32 tx_multi_collision_packet;
	u32 tx_deferred_packet;
	u32 tx_late_collision_packet;
	u32 tx_excessive_collision_packet;
	u32 tx_carrier_err_packet;
	u32 tx_octet_cnt_good;
	u32 tx_packet_cnt_good;
	u32 tx_excessive_deferral_err;
	u32 tx_pause_packet;
	u32 tx_vlan_packet_good;
	u32 tx_osize_packet_good;
	u32 reserved_0;
	u32 rx_packet_cnt_good_bad;
	u32 rx_octet_cnt_good_bad;
	u32 rx_octet_cnt_good;
	u32 rx_broadcast_packet_good;
	u32 rx_multi_packet_good;
	u32 rx_crc_err_packet;
	u32 rx_align_err_packet;
	u32 rx_runt_err_packet;
	u32 rx_jabber_err_packet;
	u32 rx_undersize_packet_good;
	u32 rx_oversize_packet_good;
	u32 rx_64_octet_packet_good_bad;
	u32 rx_65_127_octet_packet_good_bad;
	u32 rx_128_255_octet_packet_good_bad;
	u32 rx_256_511_octet_packet_good_bad;
	u32 rx_512_1023_octet_packet_good_bad;
	u32 rx_1024_max_octet_packet_good_bad;
	u32 rx_unicase_packet_good;
	u32 rx_len_err_packet;
	u32 rx_out_of_range_type_packet;
	u32 rx_pause_packet;
	u32 rx_fifo_overflow_packet;
	u32 rx_vlan_packet_good_bad;
	u32 rx_wdt_err_packet;
	u32 rx_rev_err_packet;
	u32 rx_control_packet_good;
	u32 reserved_1;
	u32 tx_lpi_micro_sec_timer;
	u32 tx_lpi_trans_cnt;
	u32 rx_lpi_micro_sec_timer;
	u32 rx_lpi_trans_cnt;
	u32 reserved_2;

	//0x800 TBD........
	u32 reserved_3[64];
};

struct dw_gmac_mac_l3_l4_regs{
	//u32 l3_l4_control;
};


struct dw_qos_mac_regs
{
	u32 config;
	u32 ext_config;
	u32 packet_filter;
	u32 wdt_timeout;
	u32 hash_table_reg[8];
	u32 reserved_0[8];
	u32 vlan_tag;
	u32 reserved_1;
	u32 vlan_hash_table;
	u32 reserved_2;
	u32 vlan_incl;
	u32 inner_vlan_incl;
	u32 reserved_3[2];
	u32 tx_flow_ctrl[8];
	u32 rx_flow_ctrl;
	u32 reserved_4;
	u32 txq_prty_map0;
	u32 txq_prty_map1;
	u32 rxq_ctrl[4];
	u32 interrupt_status;
	u32 interrupt_enable;
	u32 rx_tx_status;
	u32 reserved_5;
	u32 pmt_control_status;
	u32 rwk_packet_filter;
	u32 reserved_6[2];
	u32 lpi_control_status;
	u32 lpi_timers_control;
	u32 lpi_entry_timer;
	u32 us_tic_cnt;
	u32 an_control;
	u32 an_status;
	u32 an_advertisement;
	u32 an_link_partner_ability;
	u32 an_expansion;
	u32 tbi_extended_status;
	u32 phyif_control_status;
	u32 reserved_7[5];
	u32 version;
	u32 debug;
	u32 reserved_8;
	u32 hw_feature_0;
	u32 hw_feature_1;
	u32 hw_feature_2;
	u32 reserved_9[54];
	u32 mdio_addr;
	u32 mdio_data;
	u32 gpio_control;
	u32 gpio_status;
	u32 arp_addr;
	u32 reserved_10[59];
	struct dw_mac_addr mac_addr[128];
	struct dw_mac_mmc_regs mmc;
	//TBD 0x900...
	u32 reserved_11[192];
};

struct dw_qos_regs_map{
	struct dw_qos_mac_regs mac;
	struct dw_qos_mtl_regs mtl;
	struct dw_qos_dma_regs dma;
};

/*****************************************************************************
 *  static fun;
 *****************************************************************************/
static int fh_gmac_set_phy_register(struct dw_qos* p, int phyid ,int reg, int data);
static int fh_gmac_get_phy_register(struct dw_qos* p, int phyid, int reg);
static int dwcqos_reset_dma_hw(struct dw_qos* pGmac);
static void dwcqos_configure_bus(struct dw_qos* pGmac);
static void dwcqos_dma_tx_enable_set(struct dw_qos* pGmac, u32 dma_no, u32 enable);
static void dwcqos_dma_rx_enable_set(struct dw_qos* pGmac, u32 dma_no, u32 enable);
static void dwcqos_dma_isr_enable_set(struct dw_qos* pGmac, u32 dma_no, u32 enable);
static void dwcqos_set_hw_mac_addr(struct dw_qos* pGmac, u8* mac);
static void dwcqos_set_hw_mac_interrupt(struct dw_qos* pGmac, u32 isr);
static void dwcqos_set_hw_mac_tx_flowctrl(struct dw_qos* pGmac, u32 q_no, u32 data);
static void dwcqos_set_hw_mac_config(struct dw_qos* pGmac, u32 config);
static int dwcqos_get_hw_mac_config(struct dw_qos* pGmac);
static int dwcqos_get_hw_mtl_txqx_debug(struct dw_qos* pGmac, u32 q_no);
static int dwcqos_get_hw_mtl_rxqx_debug(struct dw_qos* pGmac, u32 q_no);
static void dwcqos_init_mtl_hw_rxdma_queue_map(struct dw_qos* pGmac);
static void debug_fix_para(struct dw_qos* pGmac);
static void parse_hw_feature(struct dw_qos* pGmac);
static void dwcqos_txq_malloc_desc(struct dw_qos* pGmac, u32 q_no, u32 malloc_size);
static void dwcqos_rxq_malloc_desc(struct dw_qos* pGmac, u32 q_no, u32 malloc_size);
static void dwcqos_rxq_desc_buf_preset(struct dw_qos* pGmac, u32 q_no, uchar *buf[], u32 buf_size);
static void dwcqos_init_sw(struct dw_qos* pGmac, u32 base_add);
static void dump_lli(struct dwcqos_dma_desc *desc, u32 size);
static void dwcqos_dma_desc_init(struct dw_qos* pGmac);
static void dwcqos_dma_chan_init(struct dw_qos* pGmac);
static void dwcqos_init_dma_hw(struct dw_qos* pGmac);
static void dwcqos_init_mtl_hw(struct dw_qos* pGmac);
static void dwcqos_mac_route_rxqueue_set(struct dw_qos* pGmac, u32 queue_no);
static void dwcqos_queue_enable_set(struct dw_qos* pGmac, u32 queue_no, u32 enable);
static void dwcqos_init_mac_hw(struct dw_qos* pGmac);
static void dwcqos_init_hw(struct dw_qos* pGmac);
static void dwcqos_kick_tx_queue(struct dw_qos* pGmac, u32 q_no);
static void dwcqos_kick_rx_queue(struct dw_qos* pGmac, u32 q_no);
static void tx_active_desc_index_init(struct dw_qos* pGmac, u32 q_no);
static void rx_active_desc_index_init(struct dw_qos* pGmac, u32 q_no);

static struct dwcqos_dma_desc  *get_rx_active_desc(struct dw_qos* pGmac, u32 q_no);
static void wait_tx_desc_done(struct dwcqos_dma_desc  *desc);
static void dump_phy_info(struct phy_device *p_phy);
static void fh_qos_mac_sync_phy_status(struct dw_qos* gmac);
static int fh_qos_mac_init_macaddr(struct eth_device* ethdev);
static int fh_qos_mac_init(struct eth_device* dev, bd_t* bd);
static void fh_qos_mac_halt(struct eth_device* dev);

static int fh_qos_mac_receive(struct eth_device* dev);
static int fh_qos_mac_miiphy_read(struct mii_dev *bus, int addr, int devad, int reg);
static int fh_qos_mac_miiphy_write(struct mii_dev *bus, int addr, int devad,
		int reg, unsigned short value);
static void fh_qos_phy_para_set(struct dw_qos *gmac);
//static int fh_gmac_qos_auto_find_phy(struct dw_qos *gmac, struct eth_device *dev);
static void fh_qos_sync_speed_duplex(struct dw_qos *gmac, int speed, int duplex);
static void dwcqos_mac_spd_port_set(struct dw_qos* pGmac, int spd);
static void dwcqos_mac_duplex_set(struct dw_qos* pGmac, int duplex);
static int qos_mac_rev_err_check(struct dwcqos_dma_desc *p_desc);
#ifdef CONFIG_FH_QOS_GMAC_SCAN_PLL
static int  qos_dll_str_to_poldll(char *s, struct pol_dll_ret *p_pol_dll);
static int loop_init(struct eth_device *p_eth, u32 spd);
static int para_dll_set(struct eth_device *p_eth, u32 tx_dll, u32 rx_dll);
static int para_pol_set(struct eth_device *p_eth, u32 tx_pol, u32 rx_pol);
static int loop_send(struct eth_device *p_eth, void *packet, u32 len);
static int loop_recv(struct eth_device *p_eth, void *buf, u32 len_wanna_be);
static char *qos_dll_poldllto_str(struct pol_dll_ret *p_pol_dll);
#endif
/*****************************************************************************
 *  extern fun;
 *****************************************************************************/
extern void fh_ephy_reset(void);
/*****************************************************************************
 * Global variables section - Local
 * define global variables(will be refered only in this file) here,
 * static keyword should be used to limit scope of local variable to this file
 * e.g.
 *  static uint8_t ufoo;
 *****************************************************************************/

static unsigned int mac_idx = 0;
#ifdef CONFIG_FH_QOS_GMAC_SCAN_PLL
#define SCAN_EACH_RX_PACKET_SIZE	2048
static __attribute__((aligned(32))) u8 g_rx_buf[SCAN_EACH_RX_PACKET_SIZE * CONFIG_SYS_RX_ETH_BUFFER] = {0};
#endif
/*****************************************************************************
 * func below..
 *****************************************************************************/

static int fh_gmac_set_phy_register(struct dw_qos* p, int phyid ,int reg, int data)
{

#ifdef CONFIG_EMULATION
	return 0;
#else
	int i = 5000;
	dw_writel(p, mac.mdio_data, data);
	dw_writel(p, mac.mdio_addr, 0x1 << 2 | phyid << 21 | 1 << 8
					| reg << 16 | 0x1);
	while ( (dw_readl(p, mac.mdio_addr) & 0x1) && i) {
		i--;
		udelay(1);
	}
	if (!i) {
		printf("set phy reg timed out!\n");
		return -1;
	}
	//printf("[write] :: reg:%08x = %08x\n",reg, data);
	return 0;
#endif
}

static int fh_gmac_get_phy_register(struct dw_qos* p, int phyid, int reg)
{

#ifdef CONFIG_EMULATION
	return 0xe3ff;
#else
	u32 ret;
	int i = 5000;

	dw_writel(p, mac.mdio_addr,
			0x3 << 2 | phyid << 21 | 1 << 8 | reg << 16 | 0x1);
	while ((dw_readl(p, mac.mdio_addr) & 0x1) && i) {
		i--;
		udelay(1);
	}
	if (!i) {
		printf("get phy reg timed out!\n");
		return 0;
	}
	ret  = dw_readl(p, mac.mdio_data);
	//printf("[read] :: reg:%08x = %08x\n",reg, ret);
	return ret;
#endif
}


static int dwcqos_reset_dma_hw(struct dw_qos* pGmac){
	int ret = -1;
	int i = 5000;
	u32 reg;
	dw_writel(pGmac, dma.mode, 1 << 0);
	do {
		i--;
		udelay(1);
		reg = dw_readl(pGmac, dma.mode);
	} while ((reg & DWCQOS_DMA_MODE_SWR) && i);
	/* We might experience a timeout if the chip clock mux is broken */
	if (!i)
		printf("DMA reset timed out!\n");
	else
		ret = 0;
	return ret;
}


static void dwcqos_configure_bus(struct dw_qos* pGmac)
{
	dw_writel(pGmac, dma.sysbus_mode, 2 << 16 | 7 << 1);
}


static void dwcqos_dma_tx_enable_set(struct dw_qos* pGmac, u32 dma_no, u32 enable)
{
	u32 ret;
	ret = dw_readl(pGmac, dma.chan[dma_no].tx_control);
	ret &= ~(1 << 0);
	ret |= (enable << 0);
	dw_writel(pGmac, dma.chan[dma_no].tx_control, ret);
}


static void dwcqos_dma_rx_enable_set(struct dw_qos* pGmac, u32 dma_no, u32 enable)
{
	u32 ret;
	ret = dw_readl(pGmac, dma.chan[dma_no].rx_control);
	ret &= ~(1 << 0);
	ret |= (enable << 0);
	dw_writel(pGmac, dma.chan[dma_no].rx_control, ret);
}

static void dwcqos_dma_isr_enable_set(struct dw_qos* pGmac, u32 dma_no, u32 enable)
{
	u32 ret;
	ret = dw_readl(pGmac, dma.chan[dma_no].interrupt_enable);
	ret &= ~(0xffff << 0);
	ret |= (enable << 0);
	dw_writel(pGmac, dma.chan[dma_no].interrupt_enable, ret);
}


static void dwcqos_set_hw_mac_addr(struct dw_qos* pGmac, u8* mac)
{
	u32 macHigh = 0;
	u32 macLow = 0;

	macHigh = mac[5] << 8 | mac[4];
	macLow = mac[3] << 24 | mac[2] << 16 | mac[1] << 8 | mac[0];

	dw_writel(pGmac, mac.mac_addr[0].addr_hi, macHigh);
	dw_writel(pGmac, mac.mac_addr[0].addr_lo, macLow);
}


void dwcqos_set_hw_mac_filter(struct dw_qos* pGmac, u32 filter)
{
	dw_writel(pGmac, mac.packet_filter, filter);
}

static void dwcqos_set_hw_mac_interrupt(struct dw_qos* pGmac, u32 isr)
{
	dw_writel(pGmac, mac.interrupt_enable, isr);
}


static void dwcqos_set_hw_mac_tx_flowctrl(struct dw_qos* pGmac, u32 q_no, u32 data)
{
	dw_writel(pGmac, mac.tx_flow_ctrl[q_no], data);
}

static void dwcqos_set_hw_mac_config(struct dw_qos* pGmac, u32 config)
{
	dw_writel(pGmac, mac.config, config);
}

static int dwcqos_get_hw_mac_config(struct dw_qos* pGmac)
{
	return dw_readl(pGmac, mac.config);
}


static int dwcqos_get_hw_mtl_txqx_debug(struct dw_qos* pGmac, u32 q_no)
{
	int ret;
	if(q_no == 0){
		ret = dw_readl(pGmac, mtl.q_0.txq_debug);
	}
	else{
		ret = dw_readl(pGmac, mtl.q_x[q_no - 1].txq_debug);
	}
	return ret;

}

static int dwcqos_get_hw_mtl_rxqx_debug(struct dw_qos* pGmac, u32 q_no)
{
	int ret;
	if(q_no == 0){
		ret = dw_readl(pGmac, mtl.q_0.rxq_debug);
	}
	else{
		ret = dw_readl(pGmac, mtl.q_x[q_no - 1].rxq_debug);
	}
	return ret;

}


void dwcqos_dma_chan_set_mss(struct dw_qos* pGmac, u32 q_no, u32 val){
	u32 ret;
	ret = dw_readl(pGmac, dma.chan[q_no].control);
	ret &= ~(0x3fff);
	ret |= (val & 0x3fff);
	dw_writel(pGmac, dma.chan[q_no].control, ret);
}



static void dwcqos_init_mtl_hw_rxdma_queue_map(struct dw_qos* pGmac){
	int q_map_0 = 0;
	int q_map_1 = 0;
	int i;

	DWCQOS_FOR_EACH_QUEUE(pGmac->hw_fea.rxq_num, i){
		if(i < 4){
			q_map_0 |= i << i * 8;
		}
		else{
			q_map_1 |= (i-4) << (i-4) * 8;
		}
	}
	dw_writel(pGmac, mtl.rxq_dma_map0, q_map_0);
	dw_writel(pGmac, mtl.rxq_dma_map1, q_map_1);

}

static void debug_fix_para(struct dw_qos* pGmac)
{
	pGmac->hw_fea.txq_num = 1;
	pGmac->hw_fea.tx_dma_num = 1;
	pGmac->hw_fea.rxq_num = 1;
	pGmac->hw_fea.rx_dma_num = 1;
}

static void parse_hw_feature(struct dw_qos* pGmac)
{
	//queue num..
	unsigned int tx_fifo_size, rx_fifo_size;

	pGmac->hw_fea.rxq_num = (pGmac->hw_fea.feature2 & 0xf) + 1;
	pGmac->hw_fea.txq_num = ((pGmac->hw_fea.feature2 >> 6) & 0xf) + 1;
	pGmac->hw_fea.tx_dma_num = ((pGmac->hw_fea.feature2 >> 18) & 0xf) + 1;
	pGmac->hw_fea.rx_dma_num = ((pGmac->hw_fea.feature2 >> 12) & 0xf) + 1;
	pGmac->hw_fea.tso_flag = (pGmac->hw_fea.feature1  & (1 << 18)) ;

	debug_fix_para(pGmac);
	//fifo size..
	tx_fifo_size  = (pGmac->hw_fea.feature1 >> 6) & 0x1f;
	rx_fifo_size = (pGmac->hw_fea.feature1 >> 0) & 0x1f;

	pGmac->hw_fea.tx_fifo_size = 128 << tx_fifo_size;
	pGmac->hw_fea.rx_fifo_size = 128 << rx_fifo_size;
	/*
	printf("[queue ] : %x : %x; [fifo size] : %x : %x\n",pGmac->hw_fea.rxq_num,pGmac->hw_fea.txq_num,
	pGmac->hw_fea.tx_fifo_size, pGmac->hw_fea.rx_fifo_size);
	printf("[dma no] :: tx : rx = %x : %x\n",pGmac->hw_fea.tx_dma_num, pGmac->hw_fea.rx_dma_num);
	*/
}


static void dwcqos_txq_malloc_desc(struct dw_qos* pGmac, u32 q_no, u32 malloc_size)
{
	u32 t1;

	pGmac->tx_queue[q_no].id = q_no;
	pGmac->tx_queue[q_no].desc_size = malloc_size;

	pGmac->tx_queue[q_no].p_raw_desc = malloc(sizeof(struct dwcqos_dma_desc) * pGmac->tx_queue[q_no].desc_size + CACHE_LINE_SIZE);
	if(!pGmac->tx_queue[q_no].p_raw_desc){
		printf("%s : %d malloc desc error..\n",__func__, __LINE__);
		FH_QOS_ASSERT(0);
	}
	t1 = (u32)pGmac->tx_queue[q_no].p_raw_desc;
	pGmac->tx_queue[q_no].p_descs = (struct dwcqos_dma_desc *)((t1 + CACHE_LINE_SIZE - 1) &
											(~(CACHE_LINE_SIZE - 1)));
	pGmac->tx_queue[q_no].descs_phy_base_addr = (u32)pGmac->tx_queue[q_no].p_descs;
	pGmac->tx_queue[q_no].descs_phy_tail_addr = pGmac->tx_queue[q_no].descs_phy_base_addr + (pGmac->tx_queue[q_no].desc_size - 1) * sizeof(struct dwcqos_dma_desc);
	pGmac->tx_queue[q_no].hw_queue_size = pGmac->hw_fea.tx_fifo_size / pGmac->hw_fea.txq_num;
	pGmac->tx_queue[q_no].desc_xfer_max_size = MAX_EACH_DESC_XFER_SIZE;
	memset(pGmac->tx_queue[q_no].p_descs, 0 , pGmac->tx_queue[q_no].desc_size * sizeof(struct dwcqos_dma_desc));

	/*
	printf("[tx_q : %d] :: base : len : tail  = %08x : %08x : %08x	\n",q_no,
	pGmac->tx_queue[q_no].descs_phy_base_addr,
	pGmac->tx_queue[q_no].desc_size,
	pGmac->tx_queue[q_no].descs_phy_tail_addr);
	*/
}


static void dwcqos_rxq_malloc_desc(struct dw_qos* pGmac, u32 q_no, u32 malloc_size)
{
	u32 t1;

	pGmac->rx_queue[q_no].id = q_no;
	pGmac->rx_queue[q_no].desc_size = malloc_size;

	pGmac->rx_queue[q_no].p_raw_desc = malloc(sizeof(struct dwcqos_dma_desc) * pGmac->rx_queue[q_no].desc_size + CACHE_LINE_SIZE);
	if(!pGmac->rx_queue[q_no].p_raw_desc){
		printf("%s : %d malloc desc error..\n",__func__, __LINE__);
		FH_QOS_ASSERT(0);
	}
	t1 = (u32)pGmac->rx_queue[q_no].p_raw_desc;
	pGmac->rx_queue[q_no].p_descs = (struct dwcqos_dma_desc *)((t1 + CACHE_LINE_SIZE - 1) &
									(~(CACHE_LINE_SIZE - 1)));
	pGmac->rx_queue[q_no].descs_phy_base_addr = (u32)pGmac->rx_queue[q_no].p_descs;
	pGmac->rx_queue[q_no].descs_phy_tail_addr = pGmac->rx_queue[q_no].descs_phy_base_addr + (pGmac->rx_queue[q_no].desc_size - 1) * sizeof(struct dwcqos_dma_desc);

	pGmac->rx_queue[q_no].hw_queue_size = pGmac->hw_fea.rx_fifo_size / pGmac->hw_fea.rxq_num;
	memset(pGmac->rx_queue[q_no].p_descs, 0 , pGmac->rx_queue[q_no].desc_size * sizeof(struct dwcqos_dma_desc));

	/*
	printf("[rx_q : %d] :: base : len : tail  = %08x : %08x : %08x	\n",q_no,
	pGmac->rx_queue[q_no].descs_phy_base_addr,
	pGmac->rx_queue[q_no].desc_size,
	pGmac->rx_queue[q_no].descs_phy_tail_addr);
	*/

}


static void dwcqos_rxq_desc_buf_preset(struct dw_qos* pGmac, u32 q_no, uchar *buf[], u32 buf_size)
{
	int i;
	if(pGmac->rx_queue[q_no].desc_size != buf_size){
		printf("[queue : %d] size %d should == buf_size %d\n", q_no, pGmac->rx_queue[q_no].desc_size, buf_size);
		FH_QOS_ASSERT(0);
	}
	for(i = 0; i < pGmac->rx_queue[q_no].desc_size; i++){
		pGmac->rx_queue[q_no].p_descs[i].desc0 = (u32) (buf[i]);
		//printf("net_rx_packets[%d] add = %08x\n",i,(u32) (buf[i]));
		pGmac->rx_queue[q_no].p_descs[i].desc3 = DWCQOS_DMA_RDES3_BUF1V | DWCQOS_DMA_RDES3_OWN;
	}
}

int check_mac_phy_inf_adapt(struct dw_qos *gmac, int set_spd){
	//add check phy spd driver sup max speed
	u32 inf_sup = gmac->p_phy_dri->ac_reg_cfg->inf_sup;
	int max_spd;

	if(inf_sup == PHY_INTERFACE_MODE_RGMII)
		max_spd = GMAC_SPEED_1000M;
	else
		max_spd = GMAC_SPEED_100M;

	if(set_spd > max_spd){
		printf("set spd[%x] > max sup[%x]\n",set_spd, max_spd);
		FH_QOS_ASSERT(0);
	}
	return 0;
}


static void fh_qos_sync_speed_for_external_single(struct dw_qos *gmac, int speed){
	u32 inf_sup = gmac->p_phy_dri->ac_reg_cfg->inf_sup;
	//control external clk sync..
	if(gmac->p_phy_dri->ac_phy_info->ex_sync_mac_spd){
		gmac->p_phy_dri->ac_phy_info->ex_sync_mac_spd(speed,
		gmac->p_phy_dri->ac_reg_cfg);
	}
	//control external interface sync..
	/*rgmii for 1000M*/
	if(gmac->p_phy_dri->inf_set){

		switch(speed){
			case  GMAC_SPEED_1000M:
				gmac->p_phy_dri->inf_set(gmac->p_phy_dev,
				PHY_INTERFACE_MODE_RGMII);
			break;
			case  GMAC_SPEED_100M:
				if(inf_sup == PHY_INTERFACE_MODE_RGMII)
					gmac->p_phy_dri->inf_set(gmac->p_phy_dev,
					PHY_INTERFACE_MODE_MII);
				else if(inf_sup == PHY_INTERFACE_MODE_RMII)
					gmac->p_phy_dri->inf_set(gmac->p_phy_dev,
					PHY_INTERFACE_MODE_RMII);
				else
					gmac->p_phy_dri->inf_set(gmac->p_phy_dev,
					PHY_INTERFACE_MODE_MII);
			break;
			case  GMAC_SPEED_10M:
				if(inf_sup == PHY_INTERFACE_MODE_RGMII)
					gmac->p_phy_dri->inf_set(gmac->p_phy_dev,
					PHY_INTERFACE_MODE_MII);
				else if(inf_sup == PHY_INTERFACE_MODE_RMII)
					gmac->p_phy_dri->inf_set(gmac->p_phy_dev,
					PHY_INTERFACE_MODE_RMII);
				else
					gmac->p_phy_dri->inf_set(gmac->p_phy_dev,
					PHY_INTERFACE_MODE_MII);
			break;

			default:
				printf("unknow spd %x\n",speed);
			break;
		}

	}	
}

static void fh_qos_sync_speed_duplex(struct dw_qos *gmac, int speed, int duplex){

	check_mac_phy_inf_adapt(gmac, speed);
	/*set spd port*/
	dwcqos_mac_spd_port_set(gmac, speed);
	/*set duplex*/
	dwcqos_mac_duplex_set(gmac, duplex);
}

static void dwcqos_init_sw(struct dw_qos* pGmac, u32 base_add)
{
	int i;
	memset(pGmac, 0, sizeof(struct dw_qos));
	pGmac->regs = (void *)base_add;
	//pGmac->regs = (void *)0x24700000;
	pGmac->local_mac_address[0] = 10;
	pGmac->local_mac_address[1] = 20;
	pGmac->local_mac_address[2] = 30;
	pGmac->local_mac_address[3] = 40;
	pGmac->local_mac_address[4] = 50;
	pGmac->local_mac_address[5] = 60;

	pGmac->phy_id = 0;
	pGmac->duplex = GMAC_DUPLEX_FULL;
	pGmac->speed = GMAC_SPEED_100M;

	pGmac->hw_fea.feature0 = dw_readl(pGmac, mac.hw_feature_0);
	pGmac->hw_fea.feature1 = dw_readl(pGmac, mac.hw_feature_1);
	pGmac->hw_fea.feature2 = dw_readl(pGmac, mac.hw_feature_2);
	pGmac->active_queue_index = FORCE_ACTIVE_QUEUE_INDEX;
	parse_hw_feature(pGmac);
	//malloc...
	if(pGmac->active_queue_index >= pGmac->hw_fea.tx_dma_num){
		printf("MAX active queue is %d\n", pGmac->hw_fea.tx_dma_num - 1);
		FH_QOS_ASSERT(0);
	}

	pGmac->tx_queue = (struct net_tx_queue *) malloc(sizeof(struct net_tx_queue) * pGmac->hw_fea.txq_num);
	pGmac->rx_queue = (struct net_rx_queue *) malloc(sizeof(struct net_rx_queue) * pGmac->hw_fea.rxq_num);

	if(!pGmac->tx_queue || !pGmac->rx_queue){
		printf("malloc tx or rx queue failed.....\n");
		FH_QOS_ASSERT(0);
	}
	memset(pGmac->tx_queue, 0, sizeof(struct net_tx_queue) * pGmac->hw_fea.txq_num);
	memset(pGmac->rx_queue, 0, sizeof(struct net_rx_queue) * pGmac->hw_fea.rxq_num);

	DWCQOS_FOR_EACH_QUEUE(pGmac->hw_fea.txq_num, i){
		dwcqos_txq_malloc_desc(pGmac, i, TX_DESC_NUM);
	}

	DWCQOS_FOR_EACH_QUEUE(pGmac->hw_fea.rxq_num, i){
		//CAUTION!!!!! here set net_rx_packets for q1-qn..means that only one rx queue could work...
		dwcqos_rxq_malloc_desc(pGmac, i, RX_DESC_NUM);
	}

}


static void dump_lli(struct dwcqos_dma_desc *desc, u32 size)
{
	u32 i;
	printf("dump go...\n");
	for(i = 0; i < size; i++){
		printf("[desc add]  : %08x\n",(u32)&desc[i]);
		printf("data = %08x : %08x : %08x : %08x\n",desc[i].desc0,desc[i].desc1,desc[i].desc2,desc[i].desc3);
	}
}


static void dwcqos_dma_desc_init(struct dw_qos* pGmac)
{
	int i;
	//TBD sep tx and rx...
	DWCQOS_FOR_EACH_QUEUE(pGmac->hw_fea.txq_num, i){
		dw_writel(pGmac, dma.chan[i].txdesc_list_laddr, pGmac->tx_queue[i].descs_phy_base_addr);
		//do not set tail point here...or if you only have one tx desc, the hw will get in suspend mode.
		//dw_writel(pGmac, dma.chan[i].txdesc_tail_pointer, pGmac->tx_queue[i].descs_phy_tail_addr);
		dw_writel(pGmac, dma.chan[i].txdesc_ring_len, pGmac->tx_queue[i].desc_size - 1);
	}

	DWCQOS_FOR_EACH_QUEUE(pGmac->hw_fea.rxq_num, i){
		dw_writel(pGmac, dma.chan[i].rxdesc_list_laddr, pGmac->rx_queue[i].descs_phy_base_addr);
		dw_writel(pGmac, dma.chan[i].rxdesc_tail_pointer, pGmac->rx_queue[i].descs_phy_tail_addr);
		dw_writel(pGmac, dma.chan[i].rxdesc_ring_len, pGmac->rx_queue[i].desc_size - 1);
	}
}

static void dwcqos_dma_chan_init(struct dw_qos* pGmac)
{
	int i;
	int reg;
	DWCQOS_FOR_EACH_QUEUE(pGmac->hw_fea.tx_dma_num, i){
		//dma chan0 ctrl. dma chan0 tx ctrl. 
		reg = 32 << 16;
		dw_writel(pGmac, dma.chan[i].control, DWCQOS_DMA_CH_CTRL_PBLX8);
		if(pGmac->hw_fea.tso_flag)
			reg |= DWCQOS_DMA_CH_TX_TSE;
		dw_writel(pGmac, dma.chan[i].tx_control, reg);
		//dma chan0 interrupt..
		dwcqos_dma_isr_enable_set(pGmac, i, 0);
	}

	DWCQOS_FOR_EACH_QUEUE(pGmac->hw_fea.rx_dma_num, i){
		//dma rx ctrl..
		dw_writel(pGmac, dma.chan[i].rx_control, 32 << 16 | 2048 << 1);
	}


	DWCQOS_FOR_EACH_QUEUE(pGmac->hw_fea.tx_dma_num, i){
		dwcqos_dma_tx_enable_set(pGmac, i, 0);
	}

	DWCQOS_FOR_EACH_QUEUE(pGmac->hw_fea.rx_dma_num, i){
		dwcqos_dma_rx_enable_set(pGmac, i, 0);
	}

	//start dma chan with dma chan0 rx/tx ctrl.. 
	// DWCQOS_FOR_EACH_QUEUE(pGmac->hw_fea.tx_dma_num, i){
	// 	dwcqos_dma_tx_enable_set(pGmac, i, 1);
	// }

	// DWCQOS_FOR_EACH_QUEUE(pGmac->hw_fea.rx_dma_num, i){
	// 	dwcqos_dma_rx_enable_set(pGmac, i, 1);
	// }
}

static void dwcqos_init_dma_hw(struct dw_qos* pGmac)
{
	dwcqos_reset_dma_hw(pGmac);
	//3:dma_sys_bus_mode...
	dwcqos_configure_bus(pGmac);
	//4:desc....
	//5:desc ring size...
	//6:desc base add and tail addr...
	dwcqos_dma_desc_init(pGmac);
	//7:dma chan0 ctrl. dma chan0 tx ctrl. dma rx ctrl..
	//8:dma chan0 interrupt..
	//9:start dma chan with dma chan0 rx/tx ctrl.. 
	dwcqos_dma_chan_init(pGmac);
}


static void dwcqos_init_mtl_hw(struct dw_qos* pGmac)
{
	int i;
	int tx_queue_size = 0;
	int rx_queue_size = 0;
	//program tx schedule
	//rev arbitration algo
	dw_writel(pGmac, mtl.operation_mode, 0x60);
	//dw_writel(pGmac, mtl.operation_mode, 0);
	//pro dma map0 and map1
	dwcqos_init_mtl_hw_rxdma_queue_map(pGmac);
	//tx_queue_size = (pGmac->hw_fea.tx_fifo_size / pGmac->hw_fea.txq_num / 256) - 1;
	//tx queue operation...
		//1):TSF, TTC
		//2):TXQEN
		//3):TQS

	DWCQOS_FOR_EACH_QUEUE(pGmac->hw_fea.txq_num, i){
		tx_queue_size = (pGmac->tx_queue[i].hw_queue_size / 256) - 1;
		if(i == 0){
			dw_writel(pGmac, mtl.q_0.txq_operation_mode, (tx_queue_size << 16) |
			DWCQOS_MTL_TXQ_TXQEN |
			DWCQOS_MTL_TXQ_TSF);
		
			dw_writel(pGmac, mtl.q_0.txq_quantum_weight,i);
		}
		else{
			dw_writel(pGmac, mtl.q_x[i - 1].txq_operation_mode, (tx_queue_size << 16) |
			DWCQOS_MTL_TXQ_TXQEN |
			DWCQOS_MTL_TXQ_TSF);
			dw_writel(pGmac, mtl.q_x[i - 1].txq_quantum_weight, i);
		}
	}

	//rx queue operation...
		//1):RSF, RTC
		//2):RFA RFD
		//3):FEP FUP
		//4):RQS
	DWCQOS_FOR_EACH_QUEUE(pGmac->hw_fea.rxq_num, i){
		rx_queue_size = (pGmac->rx_queue[i].hw_queue_size / 256) - 1;
		if(i == 0){
			dw_writel(pGmac, mtl.q_0.rxq_operation_mode, (rx_queue_size << 20)  | DWCQOS_MTL_RXQ_RSF | DWCQOS_MTL_RXQ_FEP);
			dw_writel(pGmac, mtl.q_0.rxq_control, i);
		}
		else{
			dw_writel(pGmac, mtl.q_x[i - 1].rxq_operation_mode, (rx_queue_size << 20) | DWCQOS_MTL_RXQ_RSF | DWCQOS_MTL_RXQ_FEP);
			dw_writel(pGmac, mtl.q_x[i - 1].rxq_control, i);
		}
	}
}

//maybe could set a map to route diff packet to diff rx queue..here all send to one queue
static void dwcqos_mac_route_rxqueue_set(struct dw_qos* pGmac, u32 queue_no)
{
	int val = queue_no << 0 | queue_no << 4 | queue_no << 8
	| queue_no << 12 | queue_no << 16 | 1 << 20;
	dw_writel(pGmac, mac.rxq_ctrl[1], val);
}

static void dwcqos_queue_enable_set(struct dw_qos* pGmac, u32 queue_no, u32 enable)
{
	int ret;
	ret = dw_readl(pGmac, mac.rxq_ctrl[0]);
	ret &= ~(3 << (queue_no * 2));
	if(enable){
		ret |= 2 << (queue_no * 2);
	}
	dw_writel(pGmac, mac.rxq_ctrl[0], ret);
}


void dwcqos_mac_tx_enable(struct dw_qos* pGmac){
	int ret;

	ret = dwcqos_get_hw_mac_config(pGmac);
	ret |= DWCQOS_MAC_TX_POS;
	dwcqos_set_hw_mac_config(pGmac, ret);
}

void dwcqos_mac_rx_enable(struct dw_qos* pGmac){
	int ret;

	ret = dwcqos_get_hw_mac_config(pGmac);
	ret |= DWCQOS_MAC_RX_POS;
	dwcqos_set_hw_mac_config(pGmac, ret);
}

static void dwcqos_mac_spd_port_set(struct dw_qos* pGmac, int spd){
	int ret;

	ret = dwcqos_get_hw_mac_config(pGmac);
	ret &= ~(3 << 14);
	if(spd < GMAC_SPEED_1000M)
		ret |= (1 << 15 | pGmac->speed << 14);
	dwcqos_set_hw_mac_config(pGmac, ret);
}

static void dwcqos_mac_duplex_set(struct dw_qos* pGmac, int duplex){
	int ret;

	ret = dwcqos_get_hw_mac_config(pGmac);
	ret &= ~(1 << 13);
	ret |= (duplex << 13);
	dwcqos_set_hw_mac_config(pGmac, ret);
}

static void dwcqos_init_mac_hw(struct dw_qos* pGmac)
{

	int i;

	//mac addr low and hi..
	dwcqos_set_hw_mac_addr(pGmac, pGmac->local_mac_address);
	//mac packet filter..
	//dwcqos_set_hw_mac_filter(pGmac, 0);
	dwcqos_set_hw_mac_filter(pGmac, 1 << 5 | 1 << 9);
	//dwcqos_set_hw_mac_filter(pGmac, 1 << 31);
	//tx_flow_ctl...

	DWCQOS_FOR_EACH_QUEUE(pGmac->hw_fea.txq_num, i){
		dwcqos_set_hw_mac_tx_flowctrl(pGmac, i, 0);
	}
	//mac interrupt..
	dwcqos_set_hw_mac_interrupt(pGmac, 0);

	//here set queue enable ??????
	// DWCQOS_FOR_EACH_QUEUE(pGmac->hw_fea.rxq_num, i){
	// 	q_enable |= 2 << (i * 2);
	// }
	// dw_writel(pGmac, mac.rxq_ctrl[0], q_enable);

	DWCQOS_FOR_EACH_QUEUE(pGmac->hw_fea.rxq_num, i){
		dwcqos_queue_enable_set(pGmac, i , 0);
	}
	
	//mac config
	dwcqos_set_hw_mac_config(pGmac, pGmac->duplex << 13 | 1 << 19 | 1 << 20 | 1 << 9);
}

static void dwcqos_init_hw(struct dw_qos* pGmac)
{
	//init dma...
	dwcqos_init_dma_hw(pGmac);
	//init mtl...
	dwcqos_init_mtl_hw(pGmac);
	//init mac...
	dwcqos_init_mac_hw(pGmac);

}


static void dwcqos_kick_tx_queue(struct dw_qos* pGmac, u32 q_no)
{
	//printf("kick tail add %08x= %x\n",q_no , pGmac->tx_queue[q_no].descs_phy_tail_addr);
	dw_writel(pGmac, dma.chan[q_no].txdesc_tail_pointer, pGmac->tx_queue[q_no].descs_phy_tail_addr);
}

static void dwcqos_kick_rx_queue(struct dw_qos* pGmac, u32 q_no)
{
	dw_writel(pGmac, dma.chan[q_no].rxdesc_tail_pointer, pGmac->rx_queue[q_no].descs_phy_tail_addr);
}


static void tx_active_desc_index_init(struct dw_qos* pGmac, u32 q_no)
{
	pGmac->tx_queue[q_no].desc_idx = 0;
}

static void rx_active_desc_index_init(struct dw_qos* pGmac, u32 q_no)
{
	pGmac->rx_queue[q_no].desc_idx = 0;
}

struct dwcqos_dma_desc  *get_tx_active_desc(struct dw_qos* pGmac, u32 q_no)
{
	struct dwcqos_dma_desc  *p_desc;

	p_desc = &pGmac->tx_queue[q_no].p_descs[pGmac->tx_queue[q_no].desc_idx];
	invalidate_dcache_range((u32)p_desc, (u32)p_desc + sizeof(struct dwcqos_dma_desc));
	//desc dma own
	if(p_desc->desc3 & DWCQOS_DMA_TDES3_OWN)
		return 0;
	memset(p_desc,0,sizeof(struct dwcqos_dma_desc));
	pGmac->tx_queue[q_no].desc_idx++;
	pGmac->tx_queue[q_no].desc_idx %= pGmac->tx_queue[q_no].desc_size;
	//printf("get tx desc add is %x\n",(u32)p_desc);
	return p_desc;
}


static struct dwcqos_dma_desc  *get_rx_active_desc(struct dw_qos* pGmac, u32 q_no)
{
	struct dwcqos_dma_desc  *p_desc;

	p_desc = &pGmac->rx_queue[q_no].p_descs[pGmac->rx_queue[q_no].desc_idx];
	invalidate_dcache_range((u32)p_desc, (u32)p_desc + sizeof(struct dwcqos_dma_desc));
	//desc dma own
	// printf("p_desc ::  desc0 - desc3 = %x : %x : %x : %x : %x\n",(int)p_desc,
	// p_desc->desc0,p_desc->desc1,p_desc->desc2,p_desc->desc3);
	if(p_desc->desc3 & DWCQOS_DMA_TDES3_OWN){
		//printf("null desc...p_desc :: desc3 = %x %x\n",(int)p_desc,p_desc->desc3);
		return 0;
	}


	pGmac->rx_queue[q_no].desc_idx++;
	pGmac->rx_queue[q_no].desc_idx %= pGmac->rx_queue[q_no].desc_size;
	//printf("get tx desc add is %x\n",(u32)p_desc);
	return p_desc;
}



static void wait_tx_desc_done(struct dwcqos_dma_desc  *desc)
{
	int i = 0;
	while (desc->desc3 & DWCQOS_DMA_TDES3_OWN)
	{
		invalidate_dcache_range((u32)desc, (u32)desc + sizeof(struct dwcqos_dma_desc));
		i++;
		udelay(1);
		if (i > GMAC_TIMEOUT_SEND)
		{
			printf("***ERROR: send timeout\n");
			return;
		}
	}
	if(desc->desc3 & (1 << 15)){
		printf("tx err...%x\n",desc->desc3);
	}
}


static void dump_phy_info(struct phy_device *p_phy)
{

	printf("[Addr] : %d\n[Phy Id] : %x\n[Advertising] : %x\n[Supported] : %x\n",
	p_phy->addr, p_phy->phy_id, p_phy->advertising, p_phy->supported);

	printf("[Link] is %s\n",
	p_phy->link == 1 ?"up" : "down");

	printf("[Negotiation] is %s\n",
	p_phy->autoneg == AUTONEG_ENABLE ?"enable" : "diable");

	printf("[Speed] is %dM\n",p_phy->speed);

	printf("[Duplex] is %s\n",
	p_phy->duplex == DUPLEX_FULL ?"Full" : "Half");

}

static void fh_qos_mac_sync_phy_status(struct dw_qos* gmac)
{
	struct phy_device *p_phy;
	
	p_phy = gmac->p_phy_dev;
	//dump_phy_info(p_phy);

	if(p_phy->speed == SPEED_1000)
		gmac->speed = GMAC_SPEED_1000M;
	else if(p_phy->speed == SPEED_100)
		gmac->speed = GMAC_SPEED_100M;
	else
		gmac->speed = GMAC_SPEED_10M;

	if(p_phy->duplex == DUPLEX_FULL)
		gmac->duplex = GMAC_DUPLEX_FULL;
	else
		gmac->duplex = GMAC_DUPLEX_HALF;

	if (p_phy->link == 1) {
		if(gmac->p_phy_dri->ac_phy_info->brd_link_up_cb)
			gmac->p_phy_dri->ac_phy_info->brd_link_up_cb((void *)p_phy);
	} else {
		if(gmac->p_phy_dri->ac_phy_info->brd_link_down_cb)
			gmac->p_phy_dri->ac_phy_info->brd_link_down_cb((void *)p_phy);
	}

}

static int fh_qos_mac_init_macaddr(struct eth_device* ethdev)
{
	struct dw_qos *gmac;

	gmac = (struct dw_qos *) ethdev->priv;

	memcpy(gmac->local_mac_address, ethdev->enetaddr, 6);

	dwcqos_set_hw_mac_addr(gmac, gmac->local_mac_address);

	return 0;
}



static int fh_qos_mac_init(struct eth_device* dev, bd_t* bd)
{

	struct dw_qos *gmac;

	gmac = (struct dw_qos *) dev->priv;
	dwcqos_rxq_desc_buf_preset(gmac, gmac->active_queue_index, net_rx_packets, RX_DESC_NUM);
	//because hw init .so sw desc index should set to 0.
	tx_active_desc_index_init(gmac, gmac->active_queue_index);
	memset(gmac->tx_queue[gmac->active_queue_index].p_descs,
	0 , gmac->tx_queue[gmac->active_queue_index].desc_size * sizeof(struct dwcqos_dma_desc));
	rx_active_desc_index_init(gmac, gmac->active_queue_index);
	gmac->p_phy_dri->config(gmac->p_phy_dev);
	gmac->p_phy_dri->startup(gmac->p_phy_dev);
	fh_qos_mac_sync_phy_status(gmac);
	dump_phy_info(gmac->p_phy_dev);
	//if call this func..MUST DO hw reset!!!
	fh_qos_sync_speed_for_external_single(gmac, gmac->speed);
	dwcqos_init_hw(gmac);
	fh_qos_sync_speed_duplex(gmac, gmac->speed, gmac->duplex);
	dwcqos_mac_tx_enable(gmac);
	dwcqos_mac_rx_enable(gmac);
	dwcqos_queue_enable_set(gmac, gmac->active_queue_index, 1);
	dwcqos_mac_route_rxqueue_set(gmac, gmac->active_queue_index);
	return 0;
}


#ifdef CONFIG_FH_QOS_GMAC_SCAN_PLL
static void fh_qos_dll_scan_mac_sync_phy_status(struct dw_qos* gmac)
{
	struct phy_device *p_phy;
	
	p_phy = gmac->p_phy_dev;
	//dump_phy_info(p_phy);

	if(p_phy->speed == SPEED_1000)
		gmac->speed = GMAC_SPEED_1000M;
	else if(p_phy->speed == SPEED_100)
		gmac->speed = GMAC_SPEED_100M;
	else
		gmac->speed = GMAC_SPEED_10M;

	if(p_phy->duplex == DUPLEX_FULL)
		gmac->duplex = GMAC_DUPLEX_FULL;
	else
		gmac->duplex = GMAC_DUPLEX_HALF;

}


int fh_qos_mac_scan_dll_init(struct dw_qos *gmac, uchar **pp_rx_packets, u32 packets_size, u32 spd)
{
	dwcqos_rxq_desc_buf_preset(gmac, gmac->active_queue_index, pp_rx_packets, packets_size);
	//because hw init .so sw desc index should set to 0.
	tx_active_desc_index_init(gmac, gmac->active_queue_index);
	memset(gmac->tx_queue[gmac->active_queue_index].p_descs,
	0 , gmac->tx_queue[gmac->active_queue_index].desc_size * sizeof(struct dwcqos_dma_desc));
	rx_active_desc_index_init(gmac, gmac->active_queue_index);
	gmac->p_phy_dev->speed = spd;
	gmac->p_phy_dev->duplex = DUPLEX_FULL;
	//fh_qos_mac_sync_phy_status(gmac);	
	fh_qos_dll_scan_mac_sync_phy_status(gmac);
	fh_qos_sync_speed_for_external_single(gmac, gmac->speed);
	dwcqos_init_hw(gmac);
	fh_qos_sync_speed_duplex(gmac, gmac->speed, gmac->duplex);
	dwcqos_mac_tx_enable(gmac);
	dwcqos_mac_rx_enable(gmac);
	dwcqos_queue_enable_set(gmac, gmac->active_queue_index, 1);
	dwcqos_mac_route_rxqueue_set(gmac, gmac->active_queue_index);
	return 0;
}


//0  ok
//-1 null desc
//-2 rx err
//-3 send != rev
int fh_qos_mac_receive_with_buf(struct eth_device* dev, u8 *rx_buf, u32 rx_cnt)
{
	struct dw_qos *gmac;
	int size, j;
	struct dwcqos_dma_desc  *p_desc;
	u32 queue_no;

	gmac = (struct dw_qos *) dev->priv;
	queue_no = gmac->active_queue_index;

	//for (j = 0; j < RX_DESC_NUM; j++) {
	p_desc = get_rx_active_desc(gmac, queue_no);
	if(!p_desc){
		return -1;
	}

	if(qos_mac_rev_err_check(p_desc)){
		p_desc->desc1 = 0;
		p_desc->desc2 = 0;
		p_desc->desc3 = DWCQOS_DMA_RDES3_BUF1V | DWCQOS_DMA_RDES3_OWN;
		flush_dcache_range((u32)p_desc, (u32)p_desc + sizeof(struct dwcqos_dma_desc));
		return -2;
	}

	size = p_desc->desc3 & 0x7fff;
	if(rx_cnt != (size - 4)){
		//printf("!!!!!!!!!!!!!!!rx cnt[%x] != rx size[%x]\n",rx_cnt, size);
		// debug_qos_rev_packet(p_desc);
		// print_buffer(p_desc->desc0, (void *)p_desc->desc0,
		// 4, (rx_cnt) / 4, 4);
		// printf("*******end********\n");
		p_desc->desc1 = 0;
		p_desc->desc2 = 0;
		p_desc->desc3 = DWCQOS_DMA_RDES3_BUF1V | DWCQOS_DMA_RDES3_OWN;
		flush_dcache_range((u32)p_desc, (u32)p_desc + sizeof(struct dwcqos_dma_desc));
		return -3;
	}
	memcpy(rx_buf, (u8 *)p_desc->desc0, size - 4);
	p_desc->desc1 = 0;
	p_desc->desc2 = 0;
	p_desc->desc3 = DWCQOS_DMA_RDES3_BUF1V | DWCQOS_DMA_RDES3_OWN;
	flush_dcache_range((u32)p_desc, (u32)p_desc + sizeof(struct dwcqos_dma_desc));
	//}
	return 0;
}

static void __do_phy_sw_reset(struct dw_qos *gmac){
	fh_gmac_set_phy_register(gmac, 0, 0, 0x8000);
}



static void __fh_qos_io_dll_auto_scan(struct dw_qos *gmac, struct phy_reg_cfg *p_cfg){
	int ret;
	u32 spd;
	char *str_1000M;
	char *str_100M;
	unsigned long ticket0;
	unsigned long ticket1;
	unsigned long cost;
	//struct phy_driver *p_phy_dri;
	struct pol_dll_ret best_1000M_dll = {0};
	struct pol_dll_ret best_100M_dll = {0};
	struct soc_reg_tuning soc_rec_dll = {0};
	//printf("p_cfg id is %x\n",p_cfg->id);
	if(p_cfg->inf_sup == PHY_INTERFACE_MODE_RGMII){
		str_1000M = getenv("dll_1000M");
		if(str_1000M){
			printf("got env 1000M :: %s\n",str_1000M);
			ret = qos_dll_str_to_poldll(str_1000M, &best_1000M_dll);
			if(ret){
				printf("1000M str to poldll err....\n");
				FH_QOS_ASSERT(0);
			}
			dump_pol_dll_info(&best_1000M_dll, 1, 1000);
		}else{
			printf("got no [1000M] env...need to tuning 1000M...\n");
			spd = 1000;
			ticket0 = get_ticks();
			pre_tuning_pol(gmac->ndev, gmac->p_phy_dev, spd);
			auto_tx_dll_rec(gmac->ndev, gmac->p_phy_dev, spd, &best_1000M_dll);
			//caution...need do tx first..
			auto_rx_dll_rec(gmac->ndev, gmac->p_phy_dev, spd, &best_1000M_dll);
			ticket1 = get_ticks();
			cost = ticket1 - ticket0;
			printf("1000M auto_rx_dll_rec cost [%dus]\n",(int)(cost * 10));
			//set env 1000M
			str_1000M = qos_dll_poldllto_str(&best_1000M_dll);
			if(!str_1000M){
				printf("1000M dll to str err....\n");
				FH_QOS_ASSERT(0);
			}
			setenv("dll_1000M", str_1000M);
			saveenv();
		}
	}


	str_100M = getenv("dll_100M");
	if(str_100M){
		printf("got env 100M :: %s\n",str_100M);
		ret = qos_dll_str_to_poldll(str_100M, &best_100M_dll);
		if(ret){
			printf("100M str to poldll err....\n");
			FH_QOS_ASSERT(0);
		}
		dump_pol_dll_info(&best_100M_dll, 1, 100);
	}else{
		printf("got no [100M] env...need to tuning 100M...\n");
		spd = 100;

		ticket0 = get_ticks();
		pre_tuning_pol(gmac->ndev, gmac->p_phy_dev, spd);
		auto_tx_dll_rec(gmac->ndev, gmac->p_phy_dev, spd, &best_100M_dll);
		//caution...need do tx first..
		auto_rx_dll_rec(gmac->ndev, gmac->p_phy_dev, spd, &best_100M_dll);
		ticket1 = get_ticks();
		cost = ticket1 - ticket0;
		printf("100M auto_tx_dll_rec cost [%dus]\n",(int)(cost * 10));

		str_100M = qos_dll_poldllto_str(&best_100M_dll);
		if(!str_100M){
			printf("100M dll to str err....\n");
			FH_QOS_ASSERT(0);
		}
		setenv("dll_100M", str_100M);
		saveenv();
	}

	//write to phy cfg mem
	p_cfg->tx_1000_polarity = best_1000M_dll.tx_pol;
	p_cfg->tx_1000_dll_val = best_1000M_dll.tx_dll;
	p_cfg->rx_1000_polarity = best_1000M_dll.rx_pol;
	p_cfg->rx_1000_dll_val = best_1000M_dll.rx_dll;

	p_cfg->tx_100_polarity = best_100M_dll.tx_pol;
	p_cfg->tx_100_dll_val = best_100M_dll.tx_dll;
	p_cfg->rx_100_polarity = best_100M_dll.rx_pol;
	p_cfg->rx_100_dll_val = best_100M_dll.rx_dll;
	//10M same with 100M
	p_cfg->tx_10_polarity = best_100M_dll.tx_pol;
	p_cfg->tx_10_dll_val = best_100M_dll.tx_dll;
	p_cfg->rx_10_polarity = best_100M_dll.rx_pol;
	p_cfg->rx_10_dll_val = best_100M_dll.rx_dll;


	soc_rec_dll.id_l = p_cfg->id & 0xff;
	soc_rec_dll.id_m = (p_cfg->id >> 8) & 0xff;
	soc_rec_dll.id_h = (p_cfg->id >> 16) & 0xff;;
	soc_rec_dll.area_pol = p_cfg->tx_1000_polarity << 3 | p_cfg->rx_1000_polarity << 2 |
	p_cfg->tx_100_polarity << 1 | p_cfg->rx_100_polarity;
	soc_rec_dll.area_1000_txdll = p_cfg->tx_1000_dll_val;
	soc_rec_dll.area_1000_rxdll = p_cfg->rx_1000_dll_val;
	soc_rec_dll.area_100_txdll = p_cfg->tx_100_dll_val;
	soc_rec_dll.area_100_rxdll = p_cfg->rx_100_dll_val;
	if(gmac->p_phy_dri->soc_para_set){
		gmac->p_phy_dri->soc_para_set(gmac->p_phy_dev, (void*)&soc_rec_dll);
	}
	//soc_reg_update(&soc_rec_dll);
	__do_phy_sw_reset(gmac);

}

#endif

static void fh_qos_io_dll_auto_scan(struct dw_qos *gmac){

#ifdef CONFIG_FH_QOS_GMAC_SCAN_PLL
	struct phy_reg_cfg *p_cfg;
	p_cfg = (struct phy_reg_cfg *)gmac->p_plat->p_cfg_array;
	for(; p_cfg->id != 0; p_cfg++){
		if(p_cfg->id == gmac->p_phy_dev->phy_id){

			gmac->p_phy_dri->ac_reg_cfg = p_cfg;
			gmac->p_phy_dev->drv->loop_spd_set = p_cfg->loop_spd_set;
			gmac->p_phy_dev->drv->loop_wait_linkup = p_cfg->loop_wait_linkup;
			if(p_cfg->dll_enable == DLL_SETTING_ENABLE)
				__fh_qos_io_dll_auto_scan(gmac, p_cfg);
			/*find one match;break*/
			break;
		}
	}
	if(p_cfg->id == 0){
		printf("unknow phyid [%x]..pls add board phy support..\n", gmac->p_phy_dev->phy_id);
	}
#else
	struct phy_reg_cfg *p_cfg;
	p_cfg = (struct phy_reg_cfg *)gmac->p_plat->p_cfg_array;
	for(; p_cfg->id != 0; p_cfg++){
		if(p_cfg->id == gmac->p_phy_dev->phy_id){
			if(p_cfg->inf_sup == PHY_INTERFACE_MODE_RGMII){
				printf("Warnning :: rgmii phy should do io dll scan..\n");
			}
		}
	}

#endif
}


static void fh_qos_mac_halt(struct eth_device* dev)
{
	struct dw_qos *gmac;
	int ret;
	int i = 5000;

	gmac = (struct dw_qos *) dev->priv;

	//close chx_tx_control..
	dwcqos_dma_tx_enable_set(gmac, gmac->active_queue_index , 0);
	//wait previous frame done by reading txqx_debug
	do{
		ret = dwcqos_get_hw_mtl_txqx_debug(gmac, gmac->active_queue_index);
		i--;
		if(!i) {
			printf("fh_qos_mac_halt read txqx_debug err...ret is %x\n", ret);
			return;
		}
	}while((ret & DWCQOS_MTL_TXQ_DEBUG_TRCSTS_MASK) == DWCQOS_MTL_TXQ_DEBUG_TRCSTS_READ_STATE
	|| (ret & DWCQOS_MTL_TXQ_DEBUG_TXQSTS));
	i = 5000;
	//disable mac tx and rx by setting mac_configration
	ret = dwcqos_get_hw_mac_config(gmac);
	ret &= ~(DWCQOS_MAC_RX_POS | DWCQOS_MAC_TX_POS);
	dwcqos_set_hw_mac_config(gmac, ret);
	//disable rx dma and read mtl_rxqx_debug
	dwcqos_dma_rx_enable_set(gmac, gmac->active_queue_index  , 0);
	do{
		ret = dwcqos_get_hw_mtl_rxqx_debug(gmac, gmac->active_queue_index);
		i--;
		if(!i) {
			printf("fh_qos_mac_halt read mtl_rxqx_debug err...ret is %x\n", ret);
			return;
		}
	}while((ret & DWCQOS_MTL_RXQ_DEBUG_ACTIVE_PACKET_POS_MASK) != 0
	|| (ret & DWCQOS_MTL_RXQ_DEBUG_RXQSTS_MASK) != DWCQOS_MTL_RXQ_DEBUG_RXQSTS_EMPTY);

	//makesure tx queue and rx queue empty by reading mtl_txqx_debug and mtl_rxqx_debug

	//restart should be.. DMA -> MAC tx and rx
}


void fh_qos_mac_send_with_desc(struct eth_device* dev, struct dwcqos_dma_desc  *p_tx_desc){
	struct dw_qos *gmac;
	u32 queue_no;

	gmac = (struct dw_qos *) dev->priv;
	queue_no = gmac->active_queue_index;

	dwcqos_dma_tx_enable_set(gmac, queue_no, 1);
	dwcqos_mac_tx_enable(gmac);
	dwcqos_kick_tx_queue(gmac, queue_no);
	wait_tx_desc_done(p_tx_desc);
}


int fh_qos_mac_send(struct eth_device* dev, void *packet, int length)
{
	struct dw_qos *gmac;
	u32 queue_no;

	struct dwcqos_dma_desc  *p_tx_desc;
	gmac = (struct dw_qos *) dev->priv;
	queue_no = gmac->active_queue_index;
	p_tx_desc = get_tx_active_desc(gmac, queue_no);
	if(!p_tx_desc){
		printf("get tx desc null point....\n");
		return -1;
		//FH_QOS_ASSERT(0);
	}

	invalidate_dcache_range((u32)p_tx_desc, (u32)p_tx_desc + sizeof(struct dwcqos_dma_desc));

	p_tx_desc->desc0 = (u32)packet;
	p_tx_desc->desc1 = 0;
	p_tx_desc->desc2 = length;
	p_tx_desc->desc3 = length;
	p_tx_desc->desc3 |= DWCQOS_DMA_TDES3_FD | DWCQOS_DMA_TDES3_LD | DWCQOS_DMA_TDES3_OWN;
	//dump_lli(p_tx_desc, 1);
	flush_dcache_range((u32)p_tx_desc, (u32)p_tx_desc + sizeof(struct dwcqos_dma_desc));

	dwcqos_dma_rx_enable_set(gmac, queue_no, 1);
	dwcqos_dma_tx_enable_set(gmac, queue_no, 1);
	dwcqos_kick_tx_queue(gmac, queue_no);
	dwcqos_kick_rx_queue(gmac, queue_no);
	dwcqos_mac_tx_enable(gmac);
	wait_tx_desc_done(p_tx_desc);
	//printf("tx done..\n");
	//dump_lli(p_tx_desc, 1);
	return 0;
}

// Gmac->tx_queue[q_no].desc_idx
void debug_qos_rev_packet(struct dwcqos_dma_desc *p_desc){
	printf("---[%08x] :: [%08x]---\n",p_desc->desc0, p_desc->desc3 & 0x7fff);
	print_buffer(p_desc->desc0, (void *)p_desc->desc0,
	4, (p_desc->desc3 & 0x7fff) / 4, 4);
}

static int qos_mac_rev_err_check(struct dwcqos_dma_desc *p_desc){
	if ((p_desc->desc3 & DWCQOS_DMA_RDES3_ES) ||
		(p_desc->desc1 & (DWCQOS_DMA_RDES1_IPCE | DWCQOS_DMA_RDES1_IPHE))) {
		//printf("rx err desc3 : desc1 = %x : %x\n",p_desc->desc3, p_desc->desc1);

		/*debug_qos_rev_packet(p_desc);*/
		return -1;
	}
	return 0;
}


static int fh_qos_mac_receive(struct eth_device* dev)
{
	struct dw_qos *gmac;
	int size, j;
	struct dwcqos_dma_desc  *p_desc;
	u32 queue_no;

	gmac = (struct dw_qos *) dev->priv;
	queue_no = gmac->active_queue_index;

	for (j = 0; j < RX_DESC_NUM; j++) {
		p_desc = get_rx_active_desc(gmac, queue_no);
		if(!p_desc)
			break;
		if(qos_mac_rev_err_check(p_desc)){
			p_desc->desc1 = 0;
			p_desc->desc2 = 0;
			p_desc->desc3 = DWCQOS_DMA_RDES3_BUF1V | DWCQOS_DMA_RDES3_OWN;
			flush_dcache_range((u32)p_desc, (u32)p_desc + sizeof(struct dwcqos_dma_desc));
			continue;
		}
		size = p_desc->desc3 & 0x7fff;
		//debug_qos_rev_packet(p_desc);
		net_process_received_packet((u8 *)p_desc->desc0, size - 4);

		p_desc->desc1 = 0;
		p_desc->desc2 = 0;
		p_desc->desc3 = DWCQOS_DMA_RDES3_BUF1V | DWCQOS_DMA_RDES3_OWN;
		flush_dcache_range((u32)p_desc, (u32)p_desc + sizeof(struct dwcqos_dma_desc));
	}

	return 0;
}


static int fh_qos_mac_miiphy_read(struct mii_dev *bus, int addr,
		 int devad, int reg)
{
	u16 ret;
	struct dw_qos *gmac = bus->priv;
	ret = (unsigned short)fh_gmac_get_phy_register(gmac, addr, reg);
	return ret;
}

static int fh_qos_mac_miiphy_write(struct mii_dev *bus, int addr, int devad,
		int reg, unsigned short value)
{
	struct dw_qos *gmac = bus->priv;

	return fh_gmac_set_phy_register(gmac, addr, reg, value);
}



static void fh_qos_phy_para_set(struct dw_qos *gmac)
{
	struct phy_reg_cfg *p_cfg;
	struct phy_reg_cfg_list *p_cfg_data;
	u32 ret;

	p_cfg = (struct phy_reg_cfg *)gmac->p_plat->p_cfg_array;
	for(; p_cfg->id != 0; p_cfg++){
		if(p_cfg->id == gmac->p_phy_dev->phy_id){
			/*printf("find phy id [%08x] reg para\n",p_cfg->id);*/
			//bind phy set list here..
			if(gmac->p_phy_dri->ac_reg_cfg != p_cfg)
				gmac->p_phy_dri->ac_reg_cfg = p_cfg;
			//set phy ref work clk.
			if(gmac->p_phy_dri->ac_phy_info->ex_sync_mac_spd){
				gmac->p_phy_dri->ac_phy_info->ex_sync_mac_spd(GMAC_SPEED_100M,
				gmac->p_phy_dri->ac_reg_cfg);
			}

			for(p_cfg_data = p_cfg->list; p_cfg_data->r_w != 0; p_cfg_data++){
				if(p_cfg_data->r_w == W_PHY){
					fh_gmac_set_phy_register(gmac, gmac->phy_addr, p_cfg_data->reg_add, p_cfg_data->reg_val);
				}else if(p_cfg_data->r_w == M_PHY){
					ret = fh_gmac_get_phy_register(gmac, gmac->phy_addr, p_cfg_data->reg_add);
					ret &= ~(p_cfg_data->reg_mask);
					ret |= (p_cfg_data->reg_val & p_cfg_data->reg_mask);
					fh_gmac_set_phy_register(gmac, gmac->phy_addr, p_cfg_data->reg_add, ret);
				}
			}
			/*find one match;break*/
			break;
		}
	}
	if(p_cfg->id != 0){
		printf("phy interface support %x\n",p_cfg->inf_sup);
	}

}

static int cal_phy_array_size(struct phy_reg_cfg *p_cfg)
{
	int size = 0;

	for(; p_cfg->id != 0; p_cfg++) {
		size++;
	}

	return size;
}

int phy_find_process(struct dw_qos * gmac, struct eth_device *dev){
	char* s;
	char* s_dup;
	int i;
	int au_enable = AUTONEG_ENABLE;
	unsigned int phy_sel = 0;
	struct phy_interface_info *p_phy_info;
	struct phy_driver *p_phy_dri = gmac->p_phy_dri;
	struct phy_reg_cfg *p_cfg;
	int list_size = 0;

	s_dup = getenv("force_phy_dup");
	s = getenv("force_phy_spd");

	if(s || s_dup){
		printf("force phy in speed[%s] : duplex[%s]\n",s,s_dup);
		au_enable = AUTONEG_DISABLE;
	}

	p_cfg = (struct phy_reg_cfg *)gmac->p_plat->p_cfg_array;
	if (p_cfg)
		list_size = cal_phy_array_size(p_cfg);

	for(i = 0, p_phy_info = p_phy_dri->phy_info;
	i < ARRAY_SIZE(p_phy_dri->phy_info); i++){
		//only parse usr set info.if not set ,just continue.
		if(!!p_phy_info[i].phy_sel){
			//1:pin mux
			if(p_phy_info[i].phy_sel & EXTERNAL_PHY){
				phy_sel = EXTERNAL_PHY;
			}
			else if(p_phy_info[i].phy_sel & INTERNAL_PHY)
				phy_sel = INTERNAL_PHY;
			//2:phy sel
			if(p_phy_dri->phy_sel)
				p_phy_dri->phy_sel(gmac->p_phy_dev, phy_sel);
			
			//3:phy reset
			if(p_phy_info[i].phy_reset){
				p_phy_info[i].phy_reset();
			}
			//4:mac interface set mii or rmii...sw set later,when phy auto done...
#if(0)
			if(p_phy_dri->inf_set)
				p_phy_dri->inf_set(gmac->p_phy_dev, p_phy_info[i].phy_inf);
#endif
			//5:mdio find phy
			if(p_phy_info[i].phy_inf == PHY_INTERFACE_MODE_RGMII)
				gmac->p_phy_dev = phy_device_create_with_check(gmac->p_mii_bus, gmac->p_phy_dri,\
				au_enable, PHY_GBIT_FEATURES, (void *)p_cfg, list_size);
			else
				gmac->p_phy_dev = phy_device_create_with_check(gmac->p_mii_bus, gmac->p_phy_dri,\
				au_enable, PHY_BASIC_FEATURES, (void *)p_cfg, list_size);
			//5:check result
			if (gmac->p_phy_dev){
				/*find vaild phy dev and set phy dev info..*/
				gmac->p_phy_dev->phy_inf = p_phy_info[i].phy_inf;
				gmac->p_phy_dev->phy_sel = p_phy_info[i].phy_sel;
				//bind driver active p_phy_info
				gmac->p_phy_dri->ac_phy_info = &p_phy_info[i];
				break;
			}
		}
	}
	if (!gmac->p_phy_dev){
		printf("no phy found....\n");
		return -1;
	}

	printf("find phy driver [%s]  : %s : inf ",p_phy_dri->name, 
	gmac->p_phy_dev->phy_sel == EXTERNAL_PHY ? "external phy" : "internal phy");
	if(gmac->p_phy_dev->phy_inf == PHY_INTERFACE_MODE_MII)
		printf(" mii");
	if(gmac->p_phy_dev->phy_inf == PHY_INTERFACE_MODE_RMII)
		printf(" rmii");
	if(gmac->p_phy_dev->phy_inf == PHY_INTERFACE_MODE_RGMII)
		printf(" rgmii");
	printf("\n");
	return 0;
}

int fh_gmac_qos_auto_find_phy(struct dw_qos *gmac, struct eth_device *dev){

	int i;
	struct gmac_plat_info *p_info;
	char *c_driver;
	char *s;

	//parse plat info...
	p_info = gmac->p_plat;
	if(!p_info){
		printf("NULL plat info ....\n");
		return -1;
	}

	for(i = 0, c_driver = p_info->phy_driver_list[0];
	(c_driver != 0 && i < MAX_PHY_DRIVER_SUPPORT_SIZE);
	i++, c_driver = p_info->phy_driver_list[i]){

		//bind phy driver...
		gmac->p_phy_dri = get_phy_driver_with_name(c_driver);
		if (!gmac->p_phy_dri) {
			printf("find no phy driver called [%s]\n",c_driver);
			continue;
		}
		//printf("got phy driver name [%s]\n",c_driver);
		if(!phy_find_process(gmac, dev))
			break;
	}

	if (!gmac->p_phy_dev){
		return -1;
	}


//#ifdef CONFIG_FH_QOS_GMAC_SCAN_PLL
	fh_qos_io_dll_auto_scan(gmac);
//#endif

	fh_qos_phy_para_set(gmac);

	if (gmac->p_phy_dev->autoneg == AUTONEG_DISABLE) {
		s = getenv("force_phy_spd");
		if(s){
			printf("force phy in spd[%s]\n",s);
			if(strcmp(s, "1000M") == 0)
				gmac->p_phy_dev->speed = SPEED_1000;
			else if(strcmp(s, "100M") == 0)
				gmac->p_phy_dev->speed = SPEED_100;
			else if(strcmp(s, "10M") == 0)
				gmac->p_phy_dev->speed = SPEED_10;
			else{
				printf("unknow para [%s]; use default 100M\n",s);
				gmac->p_phy_dev->speed = SPEED_100;
			}
		}
		else
		{
			printf("set default speed 100M\n");
			gmac->p_phy_dev->speed = SPEED_100;
		}
		s = getenv("force_phy_dup");
		if(s){
			printf("force phy in duplex[%s]\n",s);
			if(strcmp(s, "full") == 0)
				gmac->p_phy_dev->duplex = DUPLEX_FULL;
			else if(strcmp(s, "half") == 0)
				gmac->p_phy_dev->duplex = DUPLEX_HALF;
			else{
				printf("unknow para [%s]; use default full\n",s);
				gmac->p_phy_dev->duplex = DUPLEX_FULL;
			}
		}
		else
			gmac->p_phy_dev->duplex = DUPLEX_FULL;

	}
	gmac->p_phy_dev->dev = dev;
	gmac->p_phy_dri->config(gmac->p_phy_dev);
	s = getenv("ethact");
	if(s) {
		if (strcmp(s, gmac->ndev->name) == 0)
			gmac->p_phy_dri->startup(gmac->p_phy_dev);
	}
	return 0;
}


int fh_qos_mac_initialize(bd_t* bis)
{
	struct dw_qos *gmac;
	struct eth_device* dev;
	struct gmac_plat_info *p_info = 0;

	p_info = (struct gmac_plat_info *)get_platform_eth_info(mac_idx);
	if(!p_info){
		printf("NULL plat info\n");
		return -1;
	}
	gmac = (struct dw_qos *) malloc(sizeof(*gmac));
	if (gmac == NULL) {
		printf("fh_qos_mac_initialize: Cannot allocate driver..\n");
		return (-1);
	}
	memset(gmac, 0, sizeof(*gmac));
	dev = (struct eth_device *) malloc(sizeof(*dev));
	if (dev == NULL) {
		printf("fh_qos_mac_initialize: Cannot allocate eth_device..\n");
		free(gmac);
		return (-1);
	}
	memset(dev, 0, sizeof(*dev));
	gmac->phy_id = -1;

	
	//here board should send the control base add in...
	dwcqos_init_sw(gmac, p_info->regs);
	gmac->p_plat = p_info;
	//name maybe bind to the id..
	sprintf(dev->name, "FH_EMAC_%d",p_info->id);

	dev->init = fh_qos_mac_init;
	dev->halt = fh_qos_mac_halt;
	dev->send = fh_qos_mac_send;
	dev->recv = fh_qos_mac_receive;
	dev->write_hwaddr = fh_qos_mac_init_macaddr;
	//bind to each other
	dev->priv = (void *) gmac;
	gmac->ndev = dev;

	gmac->p_mii_bus = mdio_alloc();
	if(!gmac->p_mii_bus){
		printf("mdio malloc failed...\n");
		return -1;
	}
	gmac->p_mii_bus->priv = gmac;
	gmac->p_mii_bus->read = fh_qos_mac_miiphy_read;
	gmac->p_mii_bus->write = fh_qos_mac_miiphy_write;

#ifdef CONFIG_FH_QOS_GMAC_SCAN_PLL
	dev->loop_init = loop_init;
	dev->para_dll_set = para_dll_set;
	dev->para_pol_set = para_pol_set;
	dev->loop_send = loop_send;
	dev->loop_recv = loop_recv;	
#endif
	//name maybe bind to the id..
	sprintf(gmac->p_mii_bus->name, "fh_mii_bus_%d",p_info->id);
	if(mdio_register(gmac->p_mii_bus)){
		printf("mdio%d failed\n",p_info->id);
		return -1;
	}

	if(fh_gmac_qos_auto_find_phy(gmac, dev)){
		printf("gmac%d auto find phy failed\n",p_info->id);
		return -1;
	}

	dwcqos_reset_dma_hw(gmac);
	if(eth_register(dev))
		return -1;
	mac_idx++;
	return 0;
}

#ifdef CONFIG_FH_QOS_GMAC_SCAN_PLL
static int loop_init(struct eth_device *p_eth, u32 spd){
	int i;
	struct dw_qos *gmac = p_eth->priv;
	//printf("%s go.......\n",__func__);
	u8 *pp_buf[CONFIG_SYS_RX_ETH_BUFFER];

	for (i = 0; i < CONFIG_SYS_RX_ETH_BUFFER; i++) {
		pp_buf[i] = &g_rx_buf[i * SCAN_EACH_RX_PACKET_SIZE];
	}

	fh_qos_mac_scan_dll_init(gmac, pp_buf, CONFIG_SYS_RX_ETH_BUFFER, spd);
	dwcqos_set_hw_mac_filter(gmac, 1 << 0);
	return LOOP_OK;
}

static int para_dll_set(struct eth_device *p_eth, u32 tx_dll, u32 rx_dll){

	struct dw_qos *gmac = p_eth->priv;
	//printf("%s go.......\n",__func__);
	if(tx_dll > 0xff || rx_dll > 0xff)
		return -1;

	gmac->p_phy_dri->ac_phy_info->dll_set(tx_dll, rx_dll);
	return 0;
}


static int para_pol_set(struct eth_device *p_eth, u32 tx_pol, u32 rx_pol){

	struct dw_qos *gmac = p_eth->priv;
	//printf("%s go.......\n",__func__);
	if(tx_pol > 1 || rx_pol > 1)
		return -1;

	gmac->p_phy_dri->ac_phy_info->polarity_set(tx_pol, rx_pol);
	return 0;

}

static int loop_send(struct eth_device *p_eth, void *packet, u32 len){
	//printf("%s go.......\n",__func__);
	int ret;
	ret = fh_qos_mac_send(p_eth, packet, len);
	if(ret == 0)
		ret = LOOP_OK;
	else
		ret = LOOP_ERR_SEND;
	return ret;
}

static int loop_recv(struct eth_device *p_eth, void *buf, u32 len_wanna_be){
	int try_times = 0;
	int ret_rx;
	//printf("%s go.......\n",__func__);
	do{
		ret_rx = fh_qos_mac_receive_with_buf(p_eth, buf, len_wanna_be);
		if(ret_rx == 0)
			return LOOP_OK;
		if(ret_rx == -1){
			try_times++;
			udelay(1);
			continue;
		}
		if(ret_rx == -2){
			return LOOP_ERR_REV_ERR;
		}
		if(ret_rx == -3){
			//print_buffer((int)tuning_standard_data, (void *)tuning_standard_data, 4, sizeof(tuning_standard_data) / 4, 4);
			//printf("debug and return..\n");
			//printf("rx got less than tx...\n");
			return LOOP_ERR_REV_LEN;
		}
	}while(try_times < 10);

	if(try_times == 10){
		//printf("try timeout ....ret tx is %x\n",ret_rx);
		return LOOP_ERR_REV_TIMEOUT;
	}

	return LOOP_OK;
}


static int  qos_dll_str_to_poldll(char *s, struct pol_dll_ret *p_pol_dll)
{
	char *cp, *raw;
	int num = 0;
	u32 tmp_dl = 0;
	u8 buf[256];

	memset(buf, 0, 256);
	if (s && *s)
	{
		strcpy(buf, s);
	}
	raw = buf;
	while (raw && *raw) {
		if ((cp = strchr(raw, ':')))
			*cp++ = '\0';
		if (strlen(raw) > 0) {
			//printf("dll parse: Parameter `%s'\n", raw);
			switch (num) {
				case 0:
				if (strcmp(raw, "tx_fwd") == 0)
					p_pol_dll->tx_pol = DLL_POL_FWD;
				else
					p_pol_dll->tx_pol = DLL_POL_REV;
				break;

				case 1:
				tmp_dl = simple_strtoul(raw, NULL, 10);
				if(tmp_dl >= 0x100){
					printf("err para dll %d\n",tmp_dl);
					return -1;
				}
				p_pol_dll->tx_dll = tmp_dl;
				break;

				case 2:
				if (strcmp(raw, "rx_fwd") == 0)
					p_pol_dll->rx_pol = DLL_POL_FWD;
				else
					p_pol_dll->rx_pol = DLL_POL_REV;
				break;

				case 3:
				tmp_dl = simple_strtoul(raw, NULL, 10);
				if(tmp_dl >= 0x100){
					printf("err para dll %d\n",tmp_dl);
					return -1;
				}
				p_pol_dll->rx_dll = tmp_dl;
				break;
			}
		}
		num++;
		raw = cp;
	}
	p_pol_dll->result = "pass";
	return 0;
}



static char *qos_dll_poldllto_str(struct pol_dll_ret *p_pol_dll)
{
	static u8 ret_buf[64];
	char *p_tx_pol;
	char p_tx_dll[16] = {0};
	char *p_rx_pol;
	char p_rx_dll[16] = {0};

	if(!p_pol_dll){
		printf("%s :: NULL para get in..\n",__func__);
		return 0;
	}

	if (strcmp(p_pol_dll->result, "pass") != 0){
		printf("%s :: para get in not pass..\n",__func__);
		return 0;
	}
	//init 0 first.
	memset(ret_buf, 0, sizeof(ret_buf));
	p_tx_pol = (p_pol_dll->tx_pol == DLL_POL_FWD ? "tx_fwd" : "tx_rev");
	p_rx_pol = (p_pol_dll->rx_pol == DLL_POL_FWD ? "rx_fwd" : "rx_rev");
	sprintf(p_tx_dll, "%d",p_pol_dll->tx_dll);
	sprintf(p_rx_dll, "%d",p_pol_dll->rx_dll);
	sprintf(ret_buf, "%s:%s:%s:%s",
	p_tx_pol, p_tx_dll, p_rx_pol, p_rx_dll);
	return ret_buf;
}
#endif
